package com.shujia.day15;

import java.util.ArrayList;
import java.util.LinkedList;

public class Code10ConsumerProducerDemo {
    public static void main(String[] args) {
        // 由于面包店只能有一个 所以需要先创建一个对象
        Bakery bakery = new Bakery();

        Thread producer = new Thread(new Producer(bakery), "生产者");
        Thread consumer1 = new Thread(new Consumer(bakery), "消费者");
        Thread consumer2 = new Thread(new Consumer(bakery), "消费者");

        producer.start();
        consumer1.start();
        consumer2.start();

        /*
            对于线程通信可以使用
                wait  表示阻塞当前线程
                notify  表示从被wait阻塞的线程中唤醒一个线程
            注意：
                对于wait和notify需要再synchronized同步锁中才能够使用

         */


    }
}


// 生产者
class Producer implements Runnable {

    // 获取面包店的操作对象，并对其进行添加面包
    Bakery bakery;

    public Producer(Bakery bakery) {
        this.bakery = bakery;
    }

    @Override
    public void run() {
        // 限制生产者一天可以生产20个面包
        for (int i = 1; i <= 20; i++) {
            bakery.produceBake("蓝莓味面包");
        }
    }
}

// 消费者
class Consumer implements Runnable {

    // 获取面包店的操作对象，并对其进行消费面包
    Bakery bakery;

    public Consumer(Bakery bakery) {
        this.bakery = bakery;
    }

    @Override
    public void run() {
        // 消费者一天最多吃 15个面包
        for (int i = 1; i <= 15; i++) {
            String bake = bakery.consumerBake();
            System.out.println("消费到一个面包："+bake);
        }
    }
}


// 面包店
class Bakery {
    private LinkedList<String> linkedList = new LinkedList();  // 相当于面包的柜台

    // 对外提供两个方法 一个是购买 另一个是生产

    /*
        synchronized 对成员方法进行添加后，实际上就是对 Bakery的对象进行加锁操作
            不管是消费者还是生产者同一时刻只能有一个角色能获取到 避免了线程不安全问题
     */

    public synchronized void produceBake(String bake) {

        if (linkedList.size() >= 10) {
            // 不能对其进行生产 需要等待消费者消费之后再添加
            try {
                System.out.println("当前面包柜子满了，等消费者消费..");
                wait(); // 表示对当前的线程进行阻塞 和Sleep不同的是，如果wait不给定时间，那么就会一直处于等待状态
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        linkedList.add(bake);
        System.out.println("一个面包已经生产好了..");
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        notify();  // 从阻塞的线程中，唤醒一个消费线程
    }

    public synchronized String consumerBake() {

        if (linkedList.size() <= 0) {
            // 不能对其进行做消费 需要等待生产者生产面包
            try {
                System.out.println("当前面包柜子空了，等生产者生产..");
                wait();  // 如果面包没了 等待生产者进行生产
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        String bake = linkedList.removeLast();
        notify();  // 从阻塞的线程中，唤醒一个生产者
        return bake;

    }

}
